#ifndef STATIC_HASH_MAP
#define STATIC_HASH_MAP

#include "Exception.h"

namespace Cvekas {

template <typename Val, typename Key, size_t size>
class StaticHashMap : public boost::noncopyable
{
public:
	StaticHashMap(size_t max_items = (size / 4 * 3))
		:
	item_count(0), max_items(max_items)
	{
	}

	~StaticHashMap()
	{
	}

	bool exists(const Key& key) const
	{
		size_t id = boost::hash_value(key);
		for(size_t i = 0; i < size; ++i)
		{
			if(values[(id+i) % size].id == id)
				return true;
		}
		return false;
	}

	void set(const Val& value, const Key& key)
	{
		if(item_count >= max_items)
			throw EXCEPTION("Maximum item count reached!");

		size_t id = boost::hash_value(key);
		for(size_t i = 0; i < size; ++i)
		{
			size_t idx = (id+i) % size;
			if(values[idx].id == id)
			{
				values[idx].value = value;
				return;
			}

			if(values[idx].id == StaticHashMapItem<Val>::INVALID_ID)
			{
				values[idx].id = id;
				values[idx].value = value;
				item_count++;
				return;
			}
		}
	}

	void remove(const Key& key)
	{
		size_t id = boost::hash_value(key);
		for(size_t i = 0; i < size; ++i)
		{
			size_t idx = (id+i) % size;
			if(values[idx].id == id)
			{
				values[idx].id = StaticHashMapItem<Val>::INVALID_ID;
				item_count--;
				return;
			}
		}
		
		throw EXCEPTION("Item to remove not found!");
	}

	Val& at(const Key& key)
	{
		size_t id = boost::hash_value(key);
		for(size_t i = 0; i < size; ++i)
		{
			size_t idx = (id+i) % size;
			if(values[idx].id == id)
				return values[idx].value;
		}

		throw EXCEPTION("Item not found!");
	}

private:
	template <typename Val>
	struct StaticHashMapItem
	{
		StaticHashMapItem()
		: id(INVALID_ID)
		{}

		size_t id;
		Val value;

		static const size_t INVALID_ID = (size_t)MAX_UINT32;
	};

	boost::array<StaticHashMapItem<Val>, size> values;
	size_t item_count, max_items;
};

} // namespace

#endif